package com.lecture.junit.tdd.example;

import com.lecture.junit.tdd.example.exception.AccountAlreadyRevokedException;
import com.lecture.junit.tdd.example.exception.AccountNotFoundException;
import com.lecture.junit.tdd.example.exception.LoginException;
import com.lecture.junit.tdd.example.exception.PasswordChangeRequiredException;
import com.lecture.junit.tdd.example.util.DateUtils;

import java.util.Arrays;
import java.util.Date;

/**
 * User: Yury
 */
public abstract class LoginServiceState {


    public void login(IAccount acc, String password, LoginService context) throws LoginException {

        if (acc.passwordMatches(password)) {

            context.assureNotRevoked(acc);

            assureActionWasTakenRecently(acc, context);

            assurePasswordChangedRecently(acc, context);

            acc.setLoggedIn(true);
            acc.setLastLoginTime(new Date());
            context.setState(acc.getUserName(), new FirstFailedAttempt());
        } else {
            dealWithFailedAttempt(acc, context);
        }
    }

    private void assureActionWasTakenRecently(IAccount acc, LoginService context) throws AccountAlreadyRevokedException {
        Date lastActionDate = DateUtils.maxDate(
                acc.getLastLoginTime(),
                acc.getLastLogoutTime(),
                acc.getLastPasswordChanged()
        );
        if(lastActionDate == null){
            return;
        }
        if(context.getRequiredLastActionDate().after(lastActionDate)){
            acc.setRevoked(true);
            throw new AccountAlreadyRevokedException("Account was revoked due to no actions!");
        }
    }

    private void assurePasswordChangedRecently(IAccount acc, LoginService context) throws PasswordChangeRequiredException {
        if(acc.getLastPasswordChanged() == null){
            return;
        }
        if(context.getRequiredPasswordChangeDate().after(acc.getLastPasswordChanged())){
            throw new PasswordChangeRequiredException("Password change required!");
        }
    }



    protected abstract void dealWithFailedAttempt(IAccount acc, LoginService context);
}
